<?php
include_once ("dblib.php");
include_once("query.php");

/**
 * The purpose of this class is to handle the values of elements  on
 * our structure for being able to store nodes correctly.
 * @author CEPAL.
 * @package DataHandler
 */
class DataHandler {

    private $separador;
    private $separadorIds;
    private $nombreRaiz;
    private $tableName;
    private $nodoInterno;
    private $nodoElemento;

    /**
     * Parameters constructor
     * @param string $nombreTabla
     * @param array $parametros associative array of string:
     *  ['rel_char']
     *  ['id_char']
     *  ['tree_char']
     *  ['root_name']
     * @param bool $debug true for debug messages
     */
    function __construct($nombreTabla,$parametros,$debug=false) {
        $this->separador=$parametros['separator'];
        $this->separadorIds=$parametros['id_char'];
        $this->nombreRaiz=$parametros['root_name'];
        $this->tableName=$nombreTabla;
        $this->nodoInterno=$parametros['internal_nodes_type_name'];
        $this->nodoElemento=$parametros['element_nodes_type_name'];
        if($debug) {
            $mensaje="->TableName:$nombreTabla.<> RelSep: $this->separador.<>
            IdsSep: $this->separadorIds. <>TreeSep: $this->separador. <>Root: $this->nombreRaiz.<-";
            trigger_error($mensaje,E_USER_NOTICE);
        }
    }

    /**
     *Return the ids of an attribute with a specific property
     * @param <array of elements> $array Array of conditions in the structure
     * @param <structhandler> $gestorEstructura Struct handler object.
     * @param <bool> $debug Specific variable for debugging.
     * @return <type>
     */
    function getIdsByProperty($array,$gestorEstructura,$parametros,$debug=false) {

        if($debug) {
            $mensaje=array();
        }
        $consulta="";
        //if the array of conditions is empty, exit with NULL
        if (count($array)==0) {
            $mensaje[]="Invalid array for getIdsByProperty: cannot be empty";
            return NULL;
        }
        //For each condition in the array, the path has to be replaced with the id (structure)
        foreach ($array as $queryElement) {
            $queryElement->updateIdVar($gestorEstructura,$parametros);
        }

        //If there is only one element in the condition array...
        if (count($array)==1) {

            foreach ($array as $queryElement) {
                $consulta = "SELECT id FROM ".$this->tableName. " as t1 where ".$queryElement->getString(1).";";
            }
        }
        //if there are several conditions in the array...
        else if (count($array)>1) {

            $countarray = count($array);
            $consulta = "SELECT id FROM ".$this->tableName. " as t1 ";

            for ($i=2; $i<=$countarray; $i++) {
                $consulta = $consulta . " JOIN ". $this->tableName. " as t$i  using(id) ";
            }

            $consulta = $consulta . " where ";

            $j = 1;
            foreach ($array as $queryElement) {

                if ($j==$countarray) $consulta = $consulta . $queryElement->getString($j)  ;
                else  $consulta = $consulta . $queryElement->getString($j) ." AND ";
                $j++;
            }
        }

        $mensaje[]="Query of getIdsByProperty ".$consulta;
        //Executing the query....
        $result=DB::query($consulta);


        $resultado=array();
        $j=0;
        while($row=DB::fetch_assoc($result)) {
            $resultado[$j]=$row['id'];
            $j++;
        }
        if($debug) {
            foreach($mensaje as $mens) {
                trigger_error($mens,E_USER_NOTICE);
            }
        }
        return $resultado;
    }

    /**
     * This function returns the database table's name.
     * @return string
     */
    public function getTableName() {
        return $this->tableName;
    }

    /**
     *This function returns all differents values from a given path
     * @param <string> $path Path to extract the information.
     * @param <structhandlerobject> $shObject Structhandler object.
     * @param <bool> $debug Var to debug
     * @return <array> Array with the values.
     */
    public function getValuesFromPath($path,$shObject,$debug=false) {

        $tablaDatos=$this->tableName;
        $structID = $shObject->getId($path);
        if (($structID)>0) {
            $query = "SELECT DISTINCT VALUE FROM ".$tablaDatos." WHERE id_structure=".$structID.";";
            $salida = array();
            $result=DB::query($query);
            while($row=DB::fetch_assoc($result)) {
                $salida[$j]=$row['VALUE'];
                $j++;
            }
            return $salida;
        }
    }
    
    /**
     * This function returns the value of a node with a known path.
     * @param string $path Path of the node to return.
     * @param ElementHandler $ehObject.
     * @param StructHandler $shObject.
     * @param bool $debug true for debug messages.
     * @return string Value of the node returned.
     */
    public function getValue($path,$ehObject,$shObject,$rhObject,$debug=false) {
        if($debug) {
            $mensaje=array();
        }
        $tablaDatos=$this->tableName;
        $params=$this->parsePath($path,$ehObject,$shObject,$rhObject,$debug);
        if($params==NULL) {
            if($debug) {
                $mensaje[]="Invalid path: $path. Function will return NULL";
            }
            $resultado= NULL;
        }else {
            $query="SELECT value FROM ".$tablaDatos. " as td WHERE td.id=".$params['id']." AND td.id_structure=".$params['id_structure'];
            $result=DB::query($query);
            if(DB::num_rows($result)!=0) {
                $row=DB::fetch_assoc($result);
                if($debug) {
                    $mensaje[]="Found path: $path = ".$row['value'];
                }
                $resultado=$row['value'];
            }else {
                if($debug) {
                    $mensaje[]="Attribute doesn't exist in database: $path. Function will return NULL";
                }
                $resultado= NULL;
            }
        }
        if($debug) {
            foreach($mensaje as $mens) {
                trigger_error($mens,E_USER_NOTICE);
            }
        }
        return $resultado;
    }


    /**
     * @param string $path Path of the node to set the attribute
     * @param mixed $value Value to write.
     * @param ElementHandler $ehObject
     * @param StructHandler $shObject
     * @param bool $debug true for debug messages.
     * @return bool It returns true if the value has been written.
     */
    public function setValue($path,$value,$ehObject,$shObject,$rhObject,$debug=false) {
        if($debug) {
            $mensaje=array();
        }
        $nombreTabla=$this->tableName;
        $params=$this->parsePath($path,$ehObject,$shObject,$rhObject);
        if($params!=NULL) {
            $tipo=$shObject->getType($params['id_structure']);
            if ($tipo=='node') {
                if($debug) {
                    $mensaje[]="Invalid type($tipo): $path. Function will return false";
                }
                $resultado= false;
            }else {
                $query="REPLACE INTO ".$nombreTabla." (id,id_structure,value)
                        VALUES (".$params['id'].",".$params['id_structure'].",'".$value."')";
                $result=DB::query($query);
                if($debug) {
                    $mensaje[]="Valid path: $path. Function will return $result.";
                }
                $resultado=$result;
            }
        }else {
            if($debug) {
                $mensaje[]="Invalid path: $path. Function will return false";
            }
            $resultado=false;
        }
        if($debug) {
            foreach($mensaje as $mens) {
                trigger_error($mens,E_USER_NOTICE);
            }
        }
        return $resultado;
    }

    /**
     * It returns an array composed by each element of the path
     * @param string $path
     * @param ElementHandler $ehObject
     * @param StructHandler $shObject
     * @return array composed by each element of the path
     */
    public function parsePath($path,$ehObject,$shObject,$rhObject) {
        $campos=explode($this->separador,substr($path,1));
        $elemento="";
        $nombreEstructura="";
        $tipos="";
        $elementoEncontrado=false;
        $finElementos=false;
        $contadorElementos=0;
        $salida=array();
        foreach($campos as $campo) {
            $pos=strpos($campo,$this->separadorIds);
            if(!($pos===false)) {
                //Viene un TIPO-ID
                $elemento=$elemento.$this->separador.$campo;
                $tipos=$tipos.$this->separadorIds.substr($campo,0,$pos);
                $contadorElementos++;
                $elementoEncontrado=true;
            }else if (($elementoEncontrado)&&(!$finElementos)) {
                //Se terminaron los campos TIPO-ID/...
                if($contadorElementos==1) {
                    //Elemento simple
                    $partido=explode($this->separadorIds,substr($elemento,1));
                    $salida['id']=$partido[1];
                    $salida['type']=$partido[0];
                    $nombreEstructura=$nombreEstructura.$this->separador.$partido[0].$this->separador.$campo;
                    if(!$ehObject->exists($salida['type'].$this->separadorIds.$salida['id'])) {
                        return null;
                    }
                }
                else {
                    //Terminamos de encontrar un elemento compuesto.
                    $salida['id']=$rhObject->getId(substr($elemento,1));
                    if($salida['id']<0) {
                        return null;
                    }
                    $salida['type']=substr($tipos,1);
                    $nombreEstructura=$nombreEstructura.$this->separador.substr($tipos,1).$this->separador.$campo;
                }
                $finElementos=true;
            }else {
                //Todavia no hay elementos
                $nombreEstructura=$nombreEstructura.$this->separador.$campo;
            }
        }
        $idestructura=$shObject->getId($this->nombreRaiz.$nombreEstructura);
        if($idestructura<0) {
            return null;
        }
        $salida['id_structure']=$idestructura;
        ;
        return $salida;

    }


    /**
     * Function that deletes an atribute from the data table.
     * @param string $path
     * @return boolean true if a row has been deleted, false if any row has been deleted.
     */
    public function deleteValue($path,$ehObject,$shObject,$rhObject,$debug=false) {
        $nombreTabla=$this->tableName;
        $params=$this->parsePath($path,$ehObject,$shObject,$rhObject);
        if($params!=NULL) {
            $query="DELETE FROM ".$nombreTabla." WHERE id=".$params['id']." AND id_structure=".$params['id_structure'];
			$result=DB::query($query);
        }
        else $result=false;
        if($debug) {
            if ($result) {
                $mensaje="Value: $path Has been deleted.";
            }
            else {
                $mensaje="Value: $path Can not be deleted.";
            }
            trigger_error($mensaje,E_USER_NOTICE);
        }
        return $result;
    }


    /**
     * Function that deletes all data of the given id
     * @param integer $element_id
     * @param bool $debug for debug messages.
     * @return boolean true if any row has been deleted.
     */
    public function deleteValuesById($element_id,$debug=false) {
        $nombreTabla=$this->tableName;
        if($element_id>0) {
            $query="DELETE FROM ".$nombreTabla." WHERE id=".$element_id;
            $result=DB::query($query);
            if($debug) {
                if ($result) {
                    $mensaje="All values of element [$element_id] Have been deleted. Function will return true.";
                }
                else {
                    $mensaje="Element [$element_id] Has not any value or not exist. Function will return false.";
                }
            }
        }else {
            if($debug)$mensaje="Invalid element_id. Function will return false.";
            $result=false;
        }
        if($debug) {
            trigger_error($mensaje,E_USER_NOTICE);
        }
        return $result;
    }
}
?>
